/**
 * Copyright (c) 2015-2017, Henry Yang 杨勇 (gismail@foxmail.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lambkit.module.upms.server.interceptor;

import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.lambkit.Lambkit;
import com.lambkit.common.util.DateTimeUtils;
import com.lambkit.component.shiro.ShiroConfig;
import com.lambkit.component.shiro.session.ShiroSession;

import com.lambkit.module.upms.UpmsConfig;
import com.lambkit.module.upms.UpmsManager;
import com.lambkit.module.upms.model.UpmsLogModel;
import com.lambkit.module.upms.model.UpmsPermissionModel;
import com.lambkit.module.upms.record.UpmsLog;
import com.lambkit.module.upms.record.UpmsUser;
import com.lambkit.module.upms.shiro.ShiroCacheSessionDao;
import com.lambkit.module.upms.shiro.UpmsUsernamePasswordToken;
import com.lambkit.web.controller.log.UniqueVisitorLogService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;

/**
 * 登录信息拦截器
 */
public class UpmsInterceptor implements Interceptor {

    private static final String LAMBKIT_OSS_ALIYUN_OSS_POLICY = PropKit.get("lambkit.oss.aliyun.oss.policy");

    private ShiroConfig config = Lambkit.config(ShiroConfig.class);

    private UpmsConfig upmsConfig = Lambkit.config(UpmsConfig.class);

	public void intercept(Invocation inv) {
		// TODO Auto-generated method stub
    	Controller controller = inv.getController();
        controller.setAttr("LAMBKIT_OSS_ALIYUN_OSS_POLICY", LAMBKIT_OSS_ALIYUN_OSS_POLICY);
//    	// 登录信息
//        Subject subject = SecurityUtils.getSubject();
//        Session session = subject.getSession();
//        String serverSessionId = session.getId().toString();
//        System.out.println("sessionId: " + serverSessionId);
//        String username = (String) subject.getPrincipal();
//        if(StrKit.notBlank(username)) {
//        	UpmsUserModel upmsUser = UpmsServerManager.me().getUpmsApiService().selectUpmsUserByUsername(username);
//            c.setAttr("upmsUser", upmsUser);
//        }
//        inv.invoke();
        // 登录信息
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        System.out.println("Lambkit upms interceptor ---------------------------------");
        System.out.println("startTime      : " + DateTimeUtils.dateToString(session.getStartTimestamp()));
        System.out.println("lastAccessTime : " + DateTimeUtils.dateToString(session.getLastAccessTime()));
        System.out.println("timeout        : " + session.getTimeout());
        String serverSessionId = session.getId().toString();
        System.out.println("sessionId      : " + serverSessionId);
        String code = UpmsManager.me().getCache().getSession(serverSessionId);
        System.out.println("sessonCode     : " + code);
        String username = (String) subject.getPrincipal();
        System.out.println("username       : " + username);
        System.out.println("----------------------------------------------------------");
        if (StrKit.notBlank(username)) {
            UpmsUser upmsUser = UpmsManager.me().getUpmsApiService().selectUpmsUserByUsername(username);
            controller.setAttr("upmsUser", upmsUser);
        } else if(StrKit.notBlank(code)) {
            String[] codes = code.split("&");
            username = codes[1];
            UpmsUsernamePasswordToken talkUserNameToken = new UpmsUsernamePasswordToken(username,"", 99);
            try {
                subject.login(talkUserNameToken);
            } catch (UnknownAccountException e) {
                e.printStackTrace();
            } catch (IncorrectCredentialsException e) {
                e.printStackTrace();
            } catch (LockedAccountException e) {
                e.printStackTrace();
            } finally {
                // 更新session状态
                ShiroCacheSessionDao upmsSessionDao = Lambkit.get(ShiroCacheSessionDao.class);
                upmsSessionDao.updateStatus(serverSessionId, username, ShiroSession.OnlineStatus.on_line);
            }
        }
        boolean hasRule = false;
        if(upmsConfig.isActiveUpmsPermission()) {
            String target = inv.getActionKey();
            UpmsPermissionModel upmsPermission = UpmsPermissionModel.service().findFirstByCacheAndUri(target);
            if (upmsPermission == null) {
                upmsPermission = new UpmsPermissionModel();
                //upmsPermission.setSystemId(6L);
                upmsPermission.setType(3);
                upmsPermission.setIcon(inv.getController().getClass().getName() + "." + inv.getMethodName());
                upmsPermission.setUri(target);
                upmsPermission.setPermissionValue(target.substring(1).replaceAll("/", ":"));
                upmsPermission.setName(upmsPermission.getPermissionValue());
                upmsPermission.setStatus(0);
                upmsPermission.save();
                hasRule = true;
            } else {
                RequiresPermissions clazz = inv.getMethod().getAnnotation(RequiresPermissions.class);
                if(clazz!=null) {
                    // shiro已经给了权限
                    System.out.println("upms-permission：shiro已经给了权限");
                    hasRule = true;
                } else if (upmsPermission.getStatus() != 1) {
                    // 该接口不需要权限控制
                    System.out.println("upms-permission：该接口不需要权限控制");
                    hasRule = true;
                } else if (upmsPermission.getStatus() == -1) {
                    //System.out.println("upms-permission：该接口已锁定");
                    doProcessUnauthenticated(inv.getController());
                    return;
                } else if (StrKit.isBlank(username)) {
                    System.out.println("upms-permission：未登录");
                    doProcessUnauthenticated(inv.getController());
                    return;
                } else {
                    UpmsUser upmsUser = controller.getAttr("upmsUser");
                    if (upmsUser == null) {
                        // 未登录
                        //inv.getController().redirect("/login");
                        System.out.println("upms-permission：未登录");
                        doProcessUnauthenticated(inv.getController());
                        return;
                    } else {
                        if (UpmsManager.me().hasRule(upmsUser, upmsPermission.getPermissionId())) {
                            // 有权限
                            System.out.println("upms-permission：有权限");
                            hasRule = true;
                        } else if(UpmsManager.me().hasAnyRoles(upmsUser, "super")) {
                            // 有权限
                            System.out.println("upms-permission：超级管理员");
                            hasRule = true;
                        } else {
                            System.out.println("upms-permission：无权限");
                        }
                    }
                }
            }
        } else {
            hasRule = true;
        }

        if (hasRule) {
            long startTime = System.currentTimeMillis();
            inv.invoke();

            UpmsLogModel upmsLogModel = (UpmsLogModel) controller.getAttr("upmsLogModelForControllerAction");
            if (upmsLogModel != null) {
                long endTime = System.currentTimeMillis();
                Integer spendTime = (int) (endTime - startTime);
                upmsLogModel.setSpendTime(spendTime);
                upmsLogModel.update();
            }

            UpmsLog upmsLog = (UpmsLog) controller.getAttr("upmsLogForControllerAction");
            if (upmsLog != null) {
                long endTime = System.currentTimeMillis();
                Integer spendTime = (int) (endTime - startTime);
                upmsLog.setSpendTime(spendTime);
                UpmsManager.me().getUpmsApiService().insertUpmsLogSelective(upmsLog);
            }

            UniqueVisitorLogService uniqueVisitorLogService = Lambkit.get(UniqueVisitorLogService.class);
            if(uniqueVisitorLogService!=null) {
                uniqueVisitorLogService.log(inv.getController());
            }
        } else {
            doProcessuUnauthorization(inv.getController());
            //inv.getController().renderError(403);
        }
	}

    /**
     * 未认证处理
     *
     * @param controller
     */
    private void doProcessUnauthenticated(Controller controller) {
        //controller.redirect(config.getLoginUrl());
        StringBuffer sso_server_url = new StringBuffer(upmsConfig.getSsoServerUrl());
        //String upmsType = upmsConfig.getType();
        String url = sso_server_url.append(config.getLoginUrl()).toString();
        if(url.startsWith("//")) {
            url = url.substring(2);
        }
        if(url.startsWith("/")) {
            url = url.substring(1);
        }
        System.out.println("未认证处理, 跳转到 " + url);
        controller.redirect(url);
    }

    /**
     * 未授权处理
     *
     * @param controller
     */
    private void doProcessuUnauthorization(Controller controller) {
        //controller.renderError(403);
        String url = config.getUnauthorizedUrl();
        if(url.startsWith("/")) {
            url = url.substring(1);
        }
        System.out.println("未授权处理, 跳转到 " + url);
        controller.redirect(url);
    }

    /**
     * 强制退出
     * @param controller
     */
//    private void doProcessuSessionForceLogout(Controller controller) {
//    	SecurityUtils.getSubject().logout();
//    	if (StrKit.isBlank(config.getLoginUrl())) {
//            controller.renderError(401);
//            return;
//        }
//        String loginUrl = config.getLoginUrl() + (config.getLoginUrl().contains("?") ? "&" : "?") + "forceLogout=1";
//        try {
//			WebUtils.issueRedirect(controller.getRequest(), controller.getResponse(), loginUrl);
//		} catch (IOException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//        //controller.redirect(config.getUnauthorizedUrl());
//    }
}
